package utils

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/fwhezfwhez/errorx"
)

func CheckZeroValue(v any) bool {
	switch v.(type) {
	case int:
		return v == any(0)
	case int64:
		return v == any(int64(0))
	case int32:
		return v == any(int32(0))
	case int16:
		return v == any(int16(0))
	case int8:
		return v == any(int8(0))
	case uint:
		return v == any(uint(0))
	case uint64:
		return v == any(uint64(0))
	case uint32:
		return v == any(uint32(0))
	case uint16:
		return v == any(uint16(0))
	case uint8:
		return v == any(uint8(0))
	case string:
		return v == any("")
	}

	return false
}

func ConvertFl32(src interface{}) float32 {

	switch src.(type) {
	case float32:
		fl := src.(float32)
		return fl
	case float64:
		fl := src.(float64)
		return float32(fl)
	case int:
		intNum := src.(int)
		return float32(intNum)
	case int64:
		intNum := src.(int64)
		return float32(intNum)
	case string:
		strNum := src.(string)
		intNum, _ := strconv.ParseFloat(strNum, 32)
		return float32(intNum)
	}

	return 0
}

func ConvertFl64(src interface{}) float64 {

	switch src.(type) {
	case float32:
		fl := src.(float32)
		return float64(fl)
	case float64:
		fl := src.(float64)
		return fl
	case int:
		intNum := src.(int)
		return float64(intNum)
	case int64:
		intNum := src.(int64)
		return float64(intNum)
	case string:
		strNum := src.(string)
		intNum, _ := strconv.ParseFloat(strNum, 64)
		return float64(intNum)
	case []uint8:
		uint8Arr := src.([]uint8)
		byteArr := []byte{}
		byteArr = append(byteArr, uint8Arr...)

		strNum := string(byteArr)
		intNum, _ := strconv.ParseFloat(strNum, 64)
		return float64(intNum)
	}

	return 0
}

func Slice2Map(list []map[string]interface{}, key string) map[int]map[string]interface{} {
	res := map[int]map[string]interface{}{}

	for _, value := range list {
		keyInt := int(ConvertInt(value[key]))
		res[keyInt] = value
	}

	return res
}

func GetStrByMap(m map[string]string) string {
	var strArr []string

	for k, v := range m {
		strArr = append(strArr, k+":"+v)
	}

	return strings.Join(strArr, ",")
}

func GetIntArrByStr(str string) ([]int, error) {
	strArr := strings.Split(str, ",")
	var intArr []int

	for _, v := range strArr {
		iv, err := strconv.Atoi(v)
		if err != nil {
			return nil, errorx.Wrap(err)
		}

		intArr = append(intArr, iv)
	}

	return intArr, nil
}

func Int64s2Str(list []int64) string {
	if len(list) == 0 {
		return ""
	}

	var strS []string
	for _, el := range list {
		strS = append(strS, strconv.Itoa(int(el)))
	}

	return strings.Join(strS, ",")
}

func IntS2Str(list []int) string {
	if len(list) == 0 {
		return ""
	}

	var strS []string
	for _, el := range list {
		strS = append(strS, fmt.Sprintf("%v", el))
	}

	return strings.Join(strS, ",")
}

func IntS2Int32s(list []int) []int32 {
	res := make([]int32, 0, len(list))
	for _, el := range list {
		res = append(res, int32(el))
	}

	return res
}

func Int64s2StrS(list []int64) []string {
	strS := make([]string, 0, 5)
	for _, v := range list {
		strS = append(strS, strconv.Itoa(int(v)))
	}

	return strS
}

func Float64s2StrS(list []float64) []string {
	strS := make([]string, 0, 5)
	for _, v := range list {
		strS = append(strS, strconv.Itoa(int(v)))
	}

	return strS
}

func Float64s2Str(list []float64) string {
	strS := make([]string, 0, 5)
	for _, v := range list {
		strS = append(strS, strconv.Itoa(int(v)))
	}

	return strings.Join(strS, ",")
}

func Int32s2Int(list []int32) []int {
	res := make([]int, 0, 3)
	for _, el := range list {
		res = append(res, int(el))
	}

	return res
}

func IntS2StrS(list []int) []string {
	strS := make([]string, 0, 5)
	for _, v := range list {
		strS = append(strS, strconv.Itoa(v))
	}

	return strS
}

func ConvertInt(src interface{}) int64 {
	switch src.(type) {
	case float32:
		fl := src.(float32)
		return int64(fl)
	case float64:
		fl := src.(float64)
		return int64(fl)
	case int:
		intNum := src.(int)
		return int64(intNum)
	case int64:
		intNum := src.(int64)
		return intNum
	case uint32:
		intNum := src.(uint32)
		return int64(intNum)
	case int32:
		intNum := src.(int32)
		return int64(intNum)
	case int16:
		intNum := src.(int16)
		return int64(intNum)
	case int8:
		intNum := src.(int8)
		return int64(intNum)
	case string:
		strNum := src.(string)
		intNum, _ := strconv.Atoi(strNum)
		return int64(intNum)
	case []uint8:
		uint8Arr := src.([]uint8)
		byteArr := []byte{}
		byteArr = append(byteArr, uint8Arr...)

		strNum := string(byteArr)
		intNum, _ := strconv.Atoi(strNum)
		return int64(intNum)
	}

	return 0
}

func StrS2int32s(arr []string) []int32 {
	result := make([]int32, 0, 3)
	for _, str := range arr {
		intS, _ := strconv.Atoi(str)
		result = append(result, int32(intS))
	}

	return result
}

func StrS2intS(arr []string) []int {
	result := make([]int, 0, 3)
	for _, str := range arr {
		intS, _ := strconv.Atoi(str)
		result = append(result, intS)
	}

	return result
}

func StrS2int64s(arr []string) []int64 {
	result := make([]int64, 0, 3)

	for _, str := range arr {
		intS, _ := strconv.Atoi(str)
		result = append(result, int64(intS))
	}

	return result
}

func Str2intS(str string) []int {
	if str == "" {
		return []int{}
	}

	strArr := strings.Split(str, ",")
	return StrS2intS(strArr)
}

func Str2int64s(str string) []int64 {
	if str == "" {
		return []int64{}
	}

	list := strings.Split(str, ",")
	return StrS2int64s(list)
}

func Str2int32s(str string) []int32 {
	if str == "" {
		return []int32{}
	}

	strArr := strings.Split(str, ",")
	return StrS2int32s(strArr)
}

func Int32s2Str(list []int32) string {
	arr := make([]string, 0, 3)
	for _, el := range list {
		arr = append(arr, strconv.Itoa(int(el)))
	}

	return strings.Join(arr, ",")
}

func GetTimeStr(t *time.Time) string {
	if t.IsZero() {
		return ""
	}

	return t.Format(time.DateTime)
}

func Byte2JsonMap(b any) map[string]interface{} {
	var jsonMap map[string]interface{}
	json.Unmarshal(b.([]byte), &jsonMap)
	return jsonMap
}
